#include "stdTcpServer.h"
#include<iostream>
#include<sys/socket.h>
#include<sys/types.h>
#include<unistd.h>
#include<pthread.h>
#include<cstring>
#include<cctype> //toupper函数，小写转大写
#include<netinet/in.h>  //sockaddr_in 结构体
#include<arpa/inet.h>// inet_pton函数
using namespace std;
struct StdTcpSocketPrivate
{
    //通信句柄
    int connfd;
    //通信是否建立成功
    bool m_connected;
};
struct StdTcpServerPrivate
{
    //监听句柄
    int sockfd;
    //服务器是否正在监听
    bool m_isRunning;
};
StdTcpServer::StdTcpServer():m_tcpAttr(new StdTcpServerPrivate),m_port(0)
{
    //是否监听
    m_tcpAttr->m_isRunning = false;
    //监听套接字
    m_tcpAttr->sockfd = -1;
}
StdTcpServer::~StdTcpServer()
{
    if(m_tcpAttr>0)
    //关闭套接字句柄
    close(m_tcpAttr->sockfd);
    m_tcpAttr->sockfd = -1;
    m_tcpAttr->m_isRunning = false;
    //释放内存
}
bool StdTcpServer::SetListen(int port)
{
    // 内部维护端口信息
    this->m_port = port;
    // 创建套接字
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1)
    {
        perror("socked error");
        throw std::runtime_error("socket create error.");
    }
    // 绑定IP和端口
    struct sockaddr_in localAddress;
    memset(&localAddress, 0, sizeof(localAddress));
    // 地址族
    localAddress.sin_family = AF_INET;
    localAddress.sin_port = htons(m_port);
    localAddress.sin_addr.s_addr = htonl(INADDR_ANY);
    //设置套接字
    m_tcpAttr->sockfd = sockfd;
    // 设置端口复用
    int optVal = 1;
    int ret =setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optVal, sizeof(optVal));
    if (ret != 0)
    {
        perror("bind error:");
        throw std::runtime_error("setsockopt error.");
    }
    // 绑定
    ret = bind(sockfd, reinterpret_cast<const sockaddr *>(&localAddress),
               sizeof(localAddress));
    if (ret != 0)
    {
        perror("bind error:");
        throw std::runtime_error("bind error.");
    }
    // 给监听的套接字设置监听
    ret = listen(sockfd, 10);
    if (ret != 0)
    {
        perror("listen error:");
        throw std::runtime_error("listern error.");
    }
    //设置状态为：正在监听
    m_tcpAttr->m_isRunning = true;
    return true;
}
//接收连接
std::shared_ptr<stdTcpSocket> StdTcpServer::getClientSock()
{
    int clientConnfd=accept(m_tcpAttr->sockfd, NULL, NULL);
    if(clientConnfd==-1)
    {
        perror("accpet error:");
        throw std::runtime_error("accept error.");
    }
    //程序到这个地方，说明有客户端连接
    cout << "clientConnfd:" << clientConnfd << endl;
    
    auto client=std::make_shared<stdTcpSocket>();

    //套接字
    client->getSockAttr()->connfd = clientConnfd;
    client->getSockAttr()->m_connected = true;
    return client;
}

stdTcpSocket::stdTcpSocket():m_sockAttr(std::make_unique<StdTcpSocketPrivate>())
{
    //通信句柄
    m_sockAttr->connfd = -1;
    //通信是否建立
    m_sockAttr->m_connected = false;
}

stdTcpSocket::~stdTcpSocket() 
{   //关闭文件描述符
    if(m_sockAttr->connfd>0)
    {
        close(m_sockAttr->connfd);
    }
}

int stdTcpSocket::connectToServer(const char *ip, int port)
{
    //创建套接字
    int sockfd=socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd==-1)
    {
        perror("socket error:");
        //抛异常
        throw std::runtime_error("socket create error.");
    }
    m_sockAttr->connfd = sockfd;
    //连接服务器
    struct sockaddr_in serverAddress;
    memset(&serverAddress, 0, sizeof(serverAddress));
    serverAddress.sin_family = AF_INET;
    serverAddress.sin_port = htons(port);
    //将ip填入serverAddress.sin_addr.s_addr
    inet_pton(AF_INET, ip, &(serverAddress.sin_addr.s_addr));
    int ret=connect(sockfd, reinterpret_cast<const sockaddr *>(&serverAddress), sizeof(serverAddress));
    if(ret!=0)
    {
        perror("connect error:");
        //抛异常
        throw std::runtime_error("connect error.");
    }
    m_sockAttr->m_connected = true;
    return 0;
}

bool stdTcpSocket::Isconnectd() const
{
    return m_sockAttr->m_connected;
}

int stdTcpSocket::sendMessage(std::string &sendMsg)
{
    return sendMessage(sendMsg.c_str(),sendMsg.size());
}

int stdTcpSocket::sendMessage(const void *sendMsg, size_t n)
{
    return write(m_sockAttr->connfd, sendMsg, n);
}

int stdTcpSocket::recvMessage(std::string &recvMsg)
{
    return 0;
}

int stdTcpSocket::recvMessage(void *recvMsg, size_t n)
{
    return read(m_sockAttr->connfd, recvMsg, n);
}
//获取/得到属性
StdTcpSocketPrivate* stdTcpSocket::getSockAttr()
{

    return m_sockAttr.get();
}
